/*
 * Copyright (C) 2011 : Gilles Coomans 
 * 
 * This file is part of QuintEssence.
 * QuintEssence is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * QuintEssence is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with QuintEssence.  If not, see <http://www.gnu.org/licenses/>.
 */
package net.exprom.qe.fields;
import haxe.Timer;
import net.exprom.qe.fields.QEField;
//import net.exprom.qe.IQELayerable;
import net.exprom.qe.QEStack;
//import net.exprom.qe.QEModel;
import Type;
/**
 * ...
 * @author Gilles Coomans
 */

class QENode extends QEField
{
	private var modelStack:QEStack;
	//public var finaliseModel:Bool;
		
	public function new(name:String, parent:QEStack, params:Dynamic = null) 
	{
		super(name, parent, params);

	}
	
	override private function createParamStruct():Dynamic 
	{
		//modelStack = null;
		fieldType = QEFT_NODE;
		//finaliseModel = true;
		return super.createParamStruct();
	}
	
	override public function applyParameters(params:Dynamic, up:Bool = true, commonOnly:Bool = false):Void 
	{
		super.applyParameters(params, up, commonOnly);
		if (!commonOnly && Reflect.hasField(params, "model")) 
		{
			if (Std.is(params.model, Array))
			{
				var arr:Array<Dynamic> = params.model;
				if (!up)
					arr.reverse();
				for(mm in arr)
					applyStack(mm, up, commonOnly);
			}
			else
				applyStack(params.model, up, commonOnly);
		}
	}
	
	override public function setNamespace(namespace:String, name:String = null):Void
	{
		super.setNamespace(namespace, name);	
		if (modelStack != null)
			modelStack.setNamespace(path);
	}
	
	public function applyStack(model:QEStack, up:Bool = true, commonOnly:Bool = false):Void
	{
		getModelStack().applyStack(model, up, commonOnly);
	}
	
	override public function applyLayer(layer:Dynamic, up:Bool = true, commonOnly:Bool = false):Void
	{
		super.applyLayer(layer, up, commonOnly);
		if (layer == null)
		{
			if (hasSettedModel())
				getModelStack().resetLeafs();
			return;
		}
		if (Type.typeof(layer) != TObject)
			throw "QENode.applyLayer failed : Could not apply something different of an anonymous on a ModelNode: " + path;
		getModelStack().applyLayer(layer, up, commonOnly);
	}
	
	inline public function getModelStack():QEStack
	{
		if (modelStack == null)
		{
			modelStack = new QEStack(path, "modelStack");
			modelStack.setParent(this.parent);
			modelStack.rootContext = this.rootContext;
		}
		return modelStack;
	}
	
	inline public function hasSettedModel():Bool
	{
		return ((modelStack == null)?false:true);
	}
	
	override public function compilField(field:QEField, up:Bool = true, commonOnly:Bool = false):Void 
	{
		super.compilField(field, up, commonOnly);
		var mfield:QENode = cast(field, QENode);
		if (mfield.hasSettedModel())
		{
			//trace("while compiling field : " + field.path + " - on " + path + " - has setted model so applying");
			getModelStack().applyStack(mfield.getModelStack(), up, commonOnly);
		}
	}

	override public function clone(cloned:Dynamic = null):Dynamic 
	{
		if (cloned == null)
			cloned = new QENode(name, null);
		return super.clone(cloned);
	}
	
	override public function resetLeafs():Void 
	{
		super.resetLeafs();
		if (hasSettedModel())
			modelStack.resetLeafs();
	}
	
	override public function finalStruct(includeMetas:Bool = false, fixEvaluation:Bool = false, validateLeafs:Bool = false, includeDefaults:Bool = false):Dynamic 
	{
		//var time = Timer.stamp();
		var o = super.finalStruct(includeMetas, fixEvaluation, validateLeafs, includeDefaults);
		if(hasSettedModel() && parameters.visibility == QEFV_PUBLIC)
		{
			var finalNode = getModelStack().finalStruct( includeMetas, fixEvaluation, validateLeafs, includeDefaults);
			Reflect.setField(o, name, finalNode);
		}
		//message("finalStruct in (ms) : " + ((Timer.stamp() - time) * 1000));
		return o;
	}
	
	override public function compil():Void 
	{
		super.compil();
		if (hasSettedModel())
			getModelStack().compil();
	}
	
	override public function setParent(parent:QEStack):Void
	{
		super.setParent(parent);
		if (hasSettedModel())
			modelStack.setParent(parent);
	}
	
	override public function fixEvaluables():Void 
	{
		if (evaluated)
			return;
		if (hasSettedModel())
			getModelStack().fixEvaluables();
		if (hasSettedMetas())
			getMetasStack().fixEvaluables();
		evaluated = true;
	}
	
	override public function validate():Bool
	{
		var ok = super.validate();
		if (hasSettedModel())
			ok = modelStack.validate();
		return ok;
	}
}